#include "dicthandler.h"
#include "configmanager.h"
#include "encryptutil.h"

#include <QFile>
#include <QDebug>
#include <QCryptographicHash>
#include <QRandomGenerator>
#include <QSysInfo>
#include <QHostInfo>  // 用于获取主机名
#include <QDir>     
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <cstring>

// 静态缓存
QByteArray EncryptUtil::s_globalKey;
const QByteArray EncryptUtil::FIXED_IV = QByteArray("1234567890abcdef");  // 需求指定固定IV（16字节）

// Windows平台需包含系统头文件（条件编译，避免跨平台冲突）
#ifdef Q_OS_WIN
#include <windows.h>  // 用于调用GetVolumeInformationW获取磁盘标识
#endif

EncryptUtil::EncryptUtil(QObject *parent) : QObject(parent)
{
	// 缓存是空的  就加载一下
    // 初始化时从ConfigManager获取密码，生成全局密钥
	if (s_globalKey.isEmpty())	{
        ConfigManager* config = ConfigManager::getInstance();
        // 用配置中心的"加密密码"（无则用默认值），结合设备唯一标识增强安全性
        QString password = config->getValue(InputMethodGroup, "EncryptPassword", "scSmartInput_2024").toString();
        s_globalKey = generateKey();
    }
}

QByteArray EncryptUtil::generateKey(const QString &password)
{
	// 若全局密钥已存在，直接返回（单例模式，避免重复生成）
    if (!s_globalKey.isEmpty()) {
        return s_globalKey;
    }

    // 若未传密码，从ConfigManager读取（默认值兜底）
    QString finalPassword = password;
    if (finalPassword.isEmpty()) {
        ConfigManager* config = ConfigManager::getInstance();
        finalPassword = config->getValue(InputMethodGroup, "EncryptPassword", "scSmartInput_2024").toString();
    }

    // 结合设备唯一标识增强安全性（避免同密码不同设备密钥相同）
    QString deviceId = QSysInfo::machineUniqueId();
    // 条件编译
#ifdef Q_OS_WIN
    // Windows平台：调用API获取C盘（系统盘）唯一序列号（需求2.2.2核心）
    WCHAR volumeName[MAX_PATH] = {0};          // 卷名（无需使用，仅占位）
    DWORD diskSerialNumber = 0;                // 磁盘唯一序列号（核心标识）
    DWORD maxComponentLen = 0;                 // 最大文件名长度（无需使用）
    DWORD fileSystemFlags = 0;                 // 文件系统标志（无需使用）
    WCHAR fileSystemName[MAX_PATH] = {0};      // 文件系统名称（无需使用）

    // 调用Windows API获取C盘信息（L"C:\\"表示系统盘，宽字符格式）
    if (GetVolumeInformationW(
        L"C:\\",                  // 目标磁盘路径（系统盘）
        volumeName,               // 输出：卷名（忽略）
        MAX_PATH,                 // 卷名缓冲区长度
        &diskSerialNumber,        // 输出：磁盘唯一序列号（DWORD类型）
        &maxComponentLen,         // 输出：最大文件名长度（忽略）
        &fileSystemFlags,         // 输出：文件系统标志（忽略）
        fileSystemName,           // 输出：文件系统名称（忽略）
        MAX_PATH                  // 文件系统名称缓冲区长度
    )) {
        // 序列号转为16进制大写字符串（确保唯一性和可读性）
        deviceId = QString::number(diskSerialNumber, 16).toUpper();
        qInfo() << "[EncryptUtil] Windows磁盘唯一标识获取成功：" << deviceId;
    } else {
        // API调用失败：输出错误码并使用兜底方案
        DWORD errorCode = GetLastError();
        qWarning() << "[EncryptUtil] 获取Windows磁盘标识失败（错误码：" << errorCode << "），使用兜底方案";
#endif
        // 跨平台兜底：主机名 + 当前用户名（确保非Windows平台或API失败时仍有唯一标识）
        QString hostName = QHostInfo::localHostName();
        QString userName = QDir::home().dirName();  // 从家目录路径提取用户名（如"/home/user"→"user"）
        deviceId = hostName + "_" + userName;
        // 极端情况：主机名+用户名仍为空，用固定字符串兜底
        if (deviceId.isEmpty()) {
            deviceId = "fallback_device_identifier_2024";
        }
        qInfo() << "[EncryptUtil] 使用兜底设备标识：" << deviceId;
#ifdef Q_OS_WIN
    }
#endif

    // SHA-256哈希生成32字节密钥（AES-256要求）
    QString keySource = finalPassword + "_" + deviceId;  // 组合密钥源（增强随机性）
    QByteArray aesKey = QCryptographicHash::hash(keySource.toUtf8(), QCryptographicHash::Sha256);
    s_globalKey = aesKey;  // 缓存全局密钥

    qDebug() << "[EncryptUtil] AES-256密钥生成完成（长度：" << aesKey.size() << "字节，来源：" << keySource;
    return aesKey;
}

QByteArray EncryptUtil::encryptString(const QString &text, const QByteArray &key)
{	
    if (text.isEmpty() || key.size() != 32) {  // AES-256要求密钥32字节
        qWarning() << "[EncryptUtil] 加密参数无效：文本为空（" << text.isEmpty() << "）或密钥长度错误（" << key.size() << "字节）";
        return {};
    }

	// 固定IV
    QByteArray iv = FIXED_IV;
    // 数据PKCS7填充（AES-CBC要求数据长度为16字节整数倍）
    QByteArray paddedData = addPkcs7Padding(text.toUtf8(), 16);
    // 初始化OpenSSL加密上下文
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if (!ctx) {
        qWarning() << "[EncryptUtil] AES加密上下文初始化失败";
        return {};
    }

    // 初始化解密算法（AES-256-CBC，需求指定模式）
    if (EVP_EncryptInit_ex(
        ctx,
        EVP_aes_256_cbc(),  // 固定使用AES-256-CBC模式
        nullptr,            // 不使用引擎（默认）
        reinterpret_cast<const unsigned char*>(key.data()),  // 32字节密钥
        reinterpret_cast<const unsigned char*>(iv.data())    // 16字节固定IV
    ) != 1) {
        EVP_CIPHER_CTX_free(ctx);  // 失败时释放上下文
        qWarning() << "[EncryptUtil] AES加密初始化失败（密钥/IV格式错误）";
        return {};
    }

    // 执行加密
    int outLen = 0;
    int totalLen = 0;
    QByteArray encryptedData(paddedData.size() + AES_BLOCK_SIZE, 0);

    // 处理主要数据
    if (EVP_EncryptUpdate(
        ctx,
        reinterpret_cast<unsigned char*>(encryptedData.data()),  // 加密输出缓冲区
        &outLen,                                                  // 输出长度
        reinterpret_cast<const unsigned char*>(paddedData.data()),// 待加密数据
        paddedData.size()                                         // 待加密数据长度
    ) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        qWarning() << "[EncryptUtil] AES加密过程失败";
        return {};
    }
    totalLen += outLen;

    // 处理最后一块数据（含PKCS7填充）
    if (EVP_EncryptFinal_ex(
        ctx,
        reinterpret_cast<unsigned char*>(encryptedData.data()) + totalLen,  // 追加到总缓冲区
        &outLen                                                              // 最后一块长度
    ) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        qWarning() << "[EncryptUtil] AES加密最终块处理失败（填充错误）";
        return {};
    }
    totalLen += outLen;
    encryptedData.truncate(totalLen);  // 截断多余空间

    EVP_CIPHER_CTX_free(ctx);
    // 返回IV+密文（IV需要用于解密）
    return iv + encryptedData;
}

QString EncryptUtil::decryptString(const QByteArray &encryptedData, const QByteArray &key)
{
	// 入参校验：数据长度不足16字节（至少含IV）或密钥非32字节，直接返回失败
    if (encryptedData.size() < 16 || key.size() != 32) {
        qWarning() << "[EncryptUtil] 解密参数无效：数据过短（" << encryptedData.size() << "字节）或密钥长度错误";
        return "";
    }

    // 分离IV和密文（加密时存储格式：IV[16字节] + 密文[N字节]）
    QByteArray iv = encryptedData.left(16);
    QByteArray cipherData = encryptedData.mid(16);
    // 初始化OpenSSL解密上下文
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if (!ctx) {
        qWarning() << "[EncryptUtil] AES解密上下文初始化失败";
        return "";
    }

    // 初始化解密算法（AES-256-CBC，与加密模式一致）
    if (EVP_DecryptInit_ex(
        ctx,
        EVP_aes_256_cbc(),  // 固定AES-256-CBC模式
        nullptr,
        reinterpret_cast<const unsigned char*>(key.data()),  // 32字节密钥
        reinterpret_cast<const unsigned char*>(iv.data())    // 提取的IV（固定值，逻辑统一）
    ) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        qWarning() << "[EncryptUtil] AES解密初始化失败（密钥/IV不匹配）";
        return "";
    }

    // 执行解密
    int outLen = 0;
    int totalLen = 0;
    QByteArray decryptedData(cipherData.size() + AES_BLOCK_SIZE, 0);  // 预留最终块空间

    // 处理主要密文
    if (EVP_DecryptUpdate(
        ctx,
        reinterpret_cast<unsigned char*>(decryptedData.data()),  // 解密输出缓冲区
        &outLen,                                                  // 输出长度
        reinterpret_cast<const unsigned char*>(cipherData.data()),// 待解密密文
        cipherData.size()                                         // 密文长度
    ) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        qWarning() << "[EncryptUtil] AES解密过程失败（密文损坏）";
        return "";
    }
    totalLen += outLen;

    // 处理最后一块数据（自动去除PKCS7填充）
    if (EVP_DecryptFinal_ex(
        ctx,
        reinterpret_cast<unsigned char*>(decryptedData.data()) + totalLen,
        &outLen
    ) != 1) {
        EVP_CIPHER_CTX_free(ctx);
        qWarning() << "[EncryptUtil] AES解密失败（密钥错误或数据篡改）";
        return "";
    }
    totalLen += outLen;
    decryptedData.truncate(totalLen);

    // 释放资源并返回明文（去除PKCS7填充）
    EVP_CIPHER_CTX_free(ctx);
    return QString::fromUtf8(removePkcs7Padding(decryptedData));
}

QByteArray EncryptUtil::generateHash(const QByteArray &data, EncryptAlgorithm algo)
{
	if (algo == EncryptAlgorithm::SHA_256)	return QCryptographicHash::hash(data, QCryptographicHash::Sha256);
    qWarning() << "[EncryptUtil] 不支持的哈希算法";
	return QByteArray();
}

QByteArray EncryptUtil::addPkcs7Padding(const QByteArray &data, int blockSize)
{
	// 填充的pkcs7的长度
	int paddingLen = blockSize - (data.size() % blockSize);
    if (paddingLen == 0)    paddingLen = blockSize;  // 数据长度为块大小整数倍时，补满一个块
	return data + QByteArray(paddingLen, static_cast<char>(paddingLen));
}

QByteArray EncryptUtil::removePkcs7Padding(const QByteArray &data)
{
	// 校验数据有效性
    if (data.isEmpty()) {
        qWarning() << "[EncryptUtil] 去填充失败：数据为空";
        return {};
    }

    // 获取填充长度（最后一个字节的值）
    int paddingLen = static_cast<unsigned char>(data.at(data.size() - 1));
    // 校验填充长度合法性（不能大于块大小16，且不能大于数据长度）
    if (paddingLen <= 0 || paddingLen > 16 || paddingLen > data.size()) {
        qWarning() << "[EncryptUtil] 无效的PKCS7填充长度：" << paddingLen;
        return data;  // 填充无效时返回原始数据，避免崩溃
    }

    // 校验所有填充字节是否一致（防止数据篡改）
    for (int i = data.size() - paddingLen; i < data.size(); ++i) {
        if (static_cast<unsigned char>(data.at(i)) != paddingLen) {
            qWarning() << "[EncryptUtil] PKCS7填充数据不合法（存在篡改）";
            return data;
        }
    }

    // 去除填充，返回原始数据
    return data.left(data.size() - paddingLen);
}
